/**
 * 
 */
package com.xpec.c4.service.server;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.net.XSENetSession;
import com.xpec.c4.service.common.ServiceInfo;
import com.xpec.c4.service.contexts.Contexts;
import com.xpec.c4.service.contexts.ScopeType;
import com.xpec.c4.service.group.ServerGroup;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.group.transportlayer.SessionCloseNotify;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ModuleName;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;

/**
 * 服务器的相关操作
 * 
 * @author lipeilin
 * @2011-5-11 下午05:01:34
 * 
 */
public class ServerOperations {

	public static final String CLOSE_TYPE = "closeType";

	public static final String IS_ROBOT = "isRobot";

	private static final Log log = LogFactory.getLog(ServerOperations.class);

	/**
	 * 关闭某个连接
	 * 
	 * @param sessionID
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-5-11 下午05:02:10
	 */
	public static boolean sessionClose(GUID sessionID, CloseType closeType, BasicServiceModule operateModule) {
//		return sessionClose(sessionID , null ,null , closeType);
		
		if (sessionID == null) {
			return false;
		}

		XSENetSession session = ServiceInfo.getSession(sessionID);
		if(closeType != CloseType.KICK_BY_RELOGIN){
			//非重複登入做離線流程
			disconnectionLocalProcess(sessionID, closeType, operateModule);
		}
		
		//2017-08-11 觀察看看close type 是null的狀況
		if (closeType == null) {
			if (log.isErrorEnabled()) {
				log.error("Close Type Is Null!",new RuntimeException());
			}
		}

		// 通知 client 被斷線
		MessageAction.sendMessage(sessionID, MessageTypes.S_ACCOUNT_CHARACTER_KICK_BY_SERVER, closeType.getId());

		// 等一瞬間讓消息能送給 client
		try {
			Thread.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		// 有的话，就是本地关闭就行。
		if (session != null) {
			session.getParameters().put(CLOSE_TYPE, closeType);
			session.close();
			if (log.isInfoEnabled()) {
				log.info("session " + sessionID + " close by " + closeType.name());
			}
			return true;
		}
		// 否则要通知gateway断开
		else {
			SessionCloseNotify content = new SessionCloseNotify();
			content.setSessionID(sessionID);
			content.setCloseType(closeType);

			String destModuleID = PlayerCommonInfoManager.getInstance()
					.getGatewayBySessionId(sessionID);

			// 如果没有目标，就是广播(理論上給gateway就好了)
			if (destModuleID == null) {

				GroupMessage msg = new GroupMessage();
				msg.setMessageType(MessageTypes.SESSION_CLOSE);
				msg.setDestModuleID(/*destModuleID*/ ModuleName.GATEWAY);
				msg.setMessageContent(content);
				MessageAction.sendGroupMessage(msg);

				if (log.isInfoEnabled()) {
					log.info("sessionClose broadcast gateWay to close , sessionId: " + sessionID);
				}
			}
			// 有目标，但模块也存在，则发送给指定模块 (正常情形)
			else if (ServerGroup.getTransportManager().hasModule(destModuleID)) {
				GroupMessage msg = new GroupMessage();
				msg.setMessageType(MessageTypes.SESSION_CLOSE);
				msg.setDestModuleID(destModuleID);
				msg.setMessageContent(content);
				MessageAction.sendGroupMessage(msg);	
		//		log.error("sessionClose msg gateWay to close , sessionId: " + sessionID + " moduleId:" + destModuleID) ;
			}
			// 其他状况 gateway失蹤了, 只好自己開使做斷線了
			else {
				Contexts.putInContexts(CLOSE_TYPE, closeType, ScopeType.SESSION);
				Contexts.endSessionContextMessage(sessionID, closeType);
				if (log.isInfoEnabled()) {
					log.info("sessionClose not found gatewayModule , start ContextsEnd : " + sessionID);
				}
			}

		}

		if (log.isInfoEnabled()) {
			log.info("session " + sessionID + " close by " + closeType.name());
		}

		return true;
	}
	
	/**
	 * @param sessionID
	 * @param closeType
	 * 斷線本地端處理流程
	 * 發生錯誤強踢時也會處理
	 */
	public static void disconnectionLocalProcess(GUID sessionID, CloseType closeType, BasicServiceModule operateModule){
		
		//離線時判斷是否為頻道主
		//只管理Chat上比對用的資料
		//TODO: 自創頻道修改成群組  頻道主判斷拿掉
		//ChatProcessor.disconnectIsPlayerHasOwnChannel(sessionID);
	
		Contexts.broadcastSessionCloseNotify(sessionID, closeType, operateModule);
		Contexts.endSessionContextMessage(sessionID, closeType);
		
		ServiceInfo.removeSession(sessionID);
		// XSENetSessionPool.removeSession(ch);
	}
	
	/**
	 * @param sessionID
	 * @param closeType
	 * 斷線時  所有的Gateway處理流程
	 * 發生錯誤強踢時也會處理
	 */
	public static void disconnectionAllGateWayProcess(GUID sessionID){
		//刪除chat資訊和Common資訊
		GUID playerId = PlayerCommonInfoManager.getInstance().getPlayerGuidBySession(sessionID);
		GUID accountId = PlayerCommonInfoManager.getInstance().getAccountIdByPlayerGuid(playerId);
		String playerName = PlayerCommonInfoManager.getInstance().getPlayerNameByGuid(playerId);
		
//		if (log.isInfoEnabled()) {
//			log.info("Session Close Log " +  GameUtility.getCurMethodName() + " Start Remove ! AccountId = " + accountId + " | PlayerId = " + playerId + " | sessionId = " + sessionID + " | Name = " + playerName);
//		}
		PlayerCommonInfoManager.getInstance().removePlayerCommonInfo(accountId, playerId, sessionID, playerName);
//		if (log.isInfoEnabled()) {
//			log.info("Session Close Log " +  GameUtility.getCurMethodName() + " End Remove ! ");
//		}
		//將session所屬content 刪掉
//		PlayerCommonInfoManager.getInstance().setSessionContent(sessionID, null);
	}
	
	
	
	
//	/** 呼叫sessionClose的情況
//	 * 1. 玩家連線好好的, 但是遊戲邏輯要強制斷線
//	 *    - 找到對應的xsesession 然後把他close, 觸發ContextsEnd邏輯
//	 * 2. 有不知問題斷線玩家, 腳色還留在server上, 然後被server定期檢查踢除呼叫
//	      - 實體連線可能還連著(瀏覽器沒有斷掉) , 就找到session把他斷掉
//	 	  - 玩家可能實體xseSession消失, 但是sessionContext 還活著, 可能沒成功觸發contextsEnd , 再幫他做一次
//	 	  - contextsSession已經消失了, 但是玩家還在現在, 直接開始踢下線邏輯
//	 */
//	public static boolean sessionClose(GUID sessionID, GUID pGuid , GUID accID,CloseType closeType) {
//		
//		if (sessionID == null) {
//			return false;
//		}
//
//		XSENetSession session = ServiceInfo.getSession(sessionID);
//
//		// 有的话，就是本地关闭就行。
//		if (session != null) {
//			session.getParameters().put(CLOSE_TYPE, closeType);
//			session.close();
//			log.info("kick session:" + sessionID);
//			return true;
//		}
//		// 否则要通知gateway断开
//		else {
//			/*先檢查一下Contexts 本身是否已經被KO了, 是的話可能之前已經有觸發過一次ContextsEnd邏輯, 彈不知道玩家怎麼還沒下線,
//			估計傳給gateway它們也不做事, 直接送消息請login把玩家給砍了*/
//			SessionContext sessionContext = Contexts.getSessionContextsBySessionID(sessionID);
//			if(sessionContext == null){
//				log.error("sessionClose occur Session Contexts gone:" + sessionID);
//				GUID playerID = pGuid;
//				GUID accountID = accID;
//				//真的contexts已經被砍了 , 但是離線觸發曾經發生一次, 但是不知道為啥沒有斷線, 再跑一次搂
//				if(playerID == null)
//					playerID = PlayerCommonInfoManager.getInstance().getPlayerGuidBySession(sessionID);
//				if(playerID != null){
//					if(accountID == null)
//						accountID = PlayerCommonInfoManager.getInstance().getAccountIdByPlayerGuid(playerID);
//					GroupMessage msg = new GroupMessage();
//					msg.setMessageType(MessageTypes.S_PLAYER_LOGOUT_ZONE_MAIN);
//					SPlayerLogoutZone info = new SPlayerLogoutZone();
//					info.setPlayerGuid(playerID);
//					info.setAccountId(accountID);
//					info.setCloseType(closeType);
//					msg.setDestModuleID(ModuleName.LOGIN);
//					msg.setMessageContent(info);
//					MessageAction.sendGroupMessage(msg);
//				}
//				else{
//				    log.error("player in zone , but session context & plyerCommonInfo playerId is gone : " + sessionID);
//				}
//				return true;
//			}
//
//			
//			SessionCloseNotify content = new SessionCloseNotify();
//			content.setSessionID(sessionID);
//			content.setCloseType(closeType);
//
//			String destModuleID = PlayerCommonInfoManager.getInstance()
//					.getGatewayBySessionId(sessionID);
//
//			// 如果没有目标，就是广播(理論上給gateway就好了)
//			if (destModuleID == null) {
//				GroupMessage msg = new GroupMessage();
//				msg.setMessageType(MessageTypes.SESSION_CLOSE);
//				msg.setDestModuleID(/*destModuleID*/ ModuleName.GATEWAY);
//				msg.setMessageContent(content);
//				MessageAction.sendGroupMessage(msg);
//				
//				log.error("sessionClose broadcast gateWay to close , sessionId: " + sessionID);
//			}
//			// 有目标，但模块也存在，则发送给指定模块 (正常情形)
//			else if (ServerGroup.getTransportManager().hasModule(destModuleID)) {
//				GroupMessage msg = new GroupMessage();
//				msg.setMessageType(MessageTypes.SESSION_CLOSE);
//				msg.setDestModuleID(destModuleID);
//				msg.setMessageContent(content);
//				MessageAction.sendGroupMessage(msg);	
//		//		log.error("sessionClose msg gateWay to close , sessionId: " + sessionID + " moduleId:" + destModuleID) ;
//			}
//			// 其他状况 gateway失蹤了, 只好自己開使做斷線了
//			else {
//				Contexts.putInContexts(CLOSE_TYPE, closeType, ScopeType.SESSION);
//				Contexts.endSessionContextMessage(sessionID, closeType);
//				log.error("sessionClose not found gatewayModule , start ContextsEnd : " + sessionID);
//			}
//
//		}
//		return true;
//	}

	public static void putetSessionCloseType(XSENetSession session,
			CloseType closeType) {
		session.getParameters().put(ServerOperations.CLOSE_TYPE, closeType);
	}

	public static CloseType getSessionCloseType(XSENetSession session) {
		return (CloseType) session.getParameters().get(
				ServerOperations.CLOSE_TYPE);
	}

}
